package com.ruoyi.water.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.water.domain.Area;
import com.ruoyi.water.domain.AreaAnalyse;
import com.ruoyi.water.domain.AreaWarn;
import com.ruoyi.water.domain.WarnType;
import com.ruoyi.water.mapper.AreaAnalyseMapper;
import com.ruoyi.water.mapper.AreaMapper;
import com.ruoyi.water.mapper.AreaWarnMapper;
import com.ruoyi.water.mapper.WarnTypeMapper;
import com.ruoyi.water.service.IAreaWarnService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.time.LocalDate;
import java.time.ZoneId;
import java.util.Date;
import java.util.List;

/**
 * 区域告警服务实现（取消查询非空限制，空值时跳过处理）
 */
@Service
@Slf4j
public class AreaWarnServiceImpl extends ServiceImpl<AreaWarnMapper, AreaWarn> implements IAreaWarnService {

    @Autowired private AreaAnalyseMapper areaAnalyseMapper;
    @Autowired private WarnTypeMapper warnTypeMapper;
    @Autowired private AreaMapper areaMapper;

    /**
     * 按日期范围生成区域告警（100/102/103/104）
     * 查询时不限制字段非空，计算时遇空值跳过
     */
    @Override
    public boolean generateAreaWarnByDateRange(LocalDate startDate, LocalDate endDate) {
        try {
            // 1. 日期参数校验
            if (startDate == null || endDate == null || startDate.isAfter(endDate)) {
                log.error("无效日期范围：startDate={}, endDate={}", startDate, endDate);
                return false;
            }

            // 2. 转换日期格式（包含时分秒）
            Date start = Date.from(startDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
            Date end = Date.from(endDate.atTime(23, 59, 59).atZone(ZoneId.systemDefault()).toInstant());

            // 3. 获取有效区域告警类型（仅处理100/102/103/104）
            List<WarnType> validWarnTypes = warnTypeMapper.selectList(new QueryWrapper<WarnType>()
                    .eq("object", "area")
                    .in("warnType", 100, 102, 103, 104)
                    .eq("status", true));
            if (CollectionUtils.isEmpty(validWarnTypes)) {
                log.warn("未查询到有效区域告警类型（100/102/103/104），终止处理");
                return true;
            }

            // 4. 查询指定日期范围的分析数据（仅保留area_id非空限制，取消其他字段非空校验）
            List<AreaAnalyse> analyses = areaAnalyseMapper.selectList(new QueryWrapper<AreaAnalyse>()
                    .ge("analyseDate", start)
                    .le("analyseDate", end)
                    .isNotNull("areaId")); // 仅确保区域ID非空
            if (CollectionUtils.isEmpty(analyses)) {
                log.info("日期范围[{}~{}]内无分析数据，终止处理", startDate, endDate);
                return true;
            }

            // 5. 逐条处理分析数据并生成告警
            for (AreaAnalyse analyse : analyses) {
                processAnalyseData(analyse, validWarnTypes);
            }

            log.info("区域告警生成完成，共处理{}条分析数据", analyses.size());
            return true;
        } catch (Exception e) {
            log.error("生成区域告警时发生异常", e);
            return false;
        }
    }

    /**
     * 处理单条分析数据，判断所有告警类型
     */
    private void processAnalyseData(AreaAnalyse analyse, List<WarnType> warnTypes) {
        try {
            // 获取区域信息（包含三级阈值）
            Area area = areaMapper.selectById(analyse.getAreaId());
            if (area == null) {
                log.warn("分析数据[areaId={}, date={}]未找到对应区域，跳过",
                        analyse.getAreaId(), analyse.getAnalyseDate());
                return;
            }

            // 校验区域阈值非空（阈值为空则无法判断任何告警）
            Long thirdWarn = area.getThirdWarn();
            Long secondWarn = area.getSecondWarn();
            Long firstWarn = area.getFirstWarn();
            if (thirdWarn == null || secondWarn == null || firstWarn == null) {
                log.warn("区域[{}({})]的告警阈值存在空值，跳过所有告警判断",
                        area.getAreaName(), area.getId());
                return;
            }

            // 提取分析数据中的关键字段（不做非空判断，后续使用时检查）
            Double todayWaterVal = analyse.getTodayWaterVal();          // 当日进水（100号用）
            Double todayBiasPercent = analyse.getTodayBiasPercent();    // 当日漏耗（102号用）
            Double monthBiasPercent = analyse.getMonthBiasPercent();    // 环比漏耗（103号用）
            Double yearBiasPercent = analyse.getYearBiasPercent();      // 同比漏耗（104号用）

            // 遍历所有告警类型，判断是否触发
            for (WarnType warnType : warnTypes) {
                judgeAndCreateWarn(analyse, area, warnType,
                        todayWaterVal, todayBiasPercent,
                        monthBiasPercent, yearBiasPercent,
                        thirdWarn, secondWarn, firstWarn);
            }
        } catch (Exception e) {
            log.error("处理分析数据[areaId={}, date={}]时发生异常，继续处理下一条",
                    analyse.getAreaId(), analyse.getAnalyseDate(), e);
        }
    }

    /**
     * 核心判断逻辑：根据告警类型和阈值生成告警，遇空值跳过
     */
    private void judgeAndCreateWarn(AreaAnalyse analyse, Area area, WarnType warnType,
                                    Double todayWaterVal, Double todayBiasPercent,
                                    Double monthBiasPercent, Double yearBiasPercent,
                                    Long thirdWarn, Long secondWarn, Long firstWarn) {

        Integer warnTypeId = warnType.getWarnType();
        Integer warnLevel = null;
        String fieldDesc = "";  // 字段描述（用于告警信息）
        Double fieldValue = null; // 实际用于判断的字段值

        // 按告警类型分支处理（先检查字段是否为空，空则跳过）
        switch (warnTypeId) {
            case 100: // 分区无进水（当日进水≤0）
                fieldDesc = "当日进水量";
                fieldValue = todayWaterVal;
                if (fieldValue == null) {
                    log.debug("区域[{}]的{}为空，跳过100号告警判断", area.getAreaName(), fieldDesc);
                    return;
                }
                // 无进水直接触发三级告警
                if (fieldValue <= 0) {
                    warnLevel = 3;
                }
                break;
            case 102: // 当日漏耗百分比超阈值
                fieldDesc = "当日漏耗百分比";
                fieldValue = todayBiasPercent;
                if (fieldValue == null) {
                    log.debug("区域[{}]的{}为空，跳过102号告警判断", area.getAreaName(), fieldDesc);
                    return;
                }
                warnLevel = getMatchedWarnLevel(fieldValue, thirdWarn, secondWarn, firstWarn);
                break;
            case 103: // 漏耗环比百分比超阈值（使用monthBiasPercent）
                fieldDesc = "漏耗环比百分比";
                fieldValue = monthBiasPercent;
                if (fieldValue == null) {
                    log.debug("区域[{}]的{}为空，跳过103号告警判断", area.getAreaName(), fieldDesc);
                    return;
                }
                warnLevel = getMatchedWarnLevel(fieldValue, thirdWarn, secondWarn, firstWarn);
                break;
            case 104: // 漏耗同比百分比超阈值（使用yearBiasPercent）
                fieldDesc = "漏耗同比百分比";
                fieldValue = yearBiasPercent;
                if (fieldValue == null) {
                    log.debug("区域[{}]的{}为空，跳过104号告警判断", area.getAreaName(), fieldDesc);
                    return;
                }
                warnLevel = getMatchedWarnLevel(fieldValue, thirdWarn, secondWarn, firstWarn);
                break;
            default:
                log.warn("未配置处理逻辑的告警类型：{}，跳过", warnTypeId);
                return;
        }

        // 未触发任何等级的告警，直接返回
        if (warnLevel == null) {
            log.debug("区域[{}]的{}[{}]未超过阈值，不生成告警",
                    area.getAreaName(), fieldDesc, fieldValue);
            return;
        }

        // 检查是否为重复告警（同区域、同类型、同日期）
        if (isDuplicateWarn(analyse.getAreaId(), warnTypeId, analyse.getAnalyseDate())) {
            log.debug("区域[{}]的告警[类型{}，日期{}]已存在，跳过重复生成",
                    area.getAreaName(), warnTypeId, analyse.getAnalyseDate());
            return;
        }

        // 生成并保存告警记录（确保当日进水量不为空，为空则简化告警信息）
        createAndSaveAreaWarn(analyse, warnType, warnLevel, fieldDesc, fieldValue, todayWaterVal);
    }

    /**
     * 通用方法：匹配告警等级（三级→二级→一级）
     */
    private Integer getMatchedWarnLevel(Double fieldValue, Long third, Long second, Long first) {
        if (fieldValue == null) return null; // 理论上此处不会为空（已在调用前检查）
        if (fieldValue > third.doubleValue()) return 3;
        if (fieldValue > second.doubleValue()) return 2;
        if (fieldValue > first.doubleValue()) return 1;
        return null;
    }

    /**
     * 判断是否为重复告警
     */
    private boolean isDuplicateWarn(Integer areaId, Integer warnType, Date warnTime) {
        QueryWrapper<AreaWarn> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("areaId", areaId)
                .eq("warnType", warnType)
                .eq("warnTime", warnTime);
        return this.count(queryWrapper) > 0;
    }

    /**
     * 构建并保存告警记录（兼容todayWaterVal为空的情况）
     */
    private void createAndSaveAreaWarn(AreaAnalyse analyse, WarnType warnType,
                                       Integer warnLevel, String fieldDesc,
                                       Double fieldValue, Double todayWaterVal) {
        AreaWarn warn = new AreaWarn();
        // 基础关联字段
        warn.setAreaId(analyse.getAreaId());
        warn.setAreaName(analyse.getAreaName());
        warn.setWarnType(warnType.getWarnType());
        warn.setWarnLevel(warnLevel);
        warn.setWarnTime(analyse.getAnalyseDate());
        // 告警信息（兼容当日进水量为空的情况）
        String waterValStr = (todayWaterVal != null) ? String.format("%.2f", todayWaterVal) : "未知";
        warn.setWarnMsg(String.format("%s，%s为%.2f%%，当日进水量%s",
                warnType.getWarnName(), fieldDesc, fieldValue, waterValStr));
        // 状态字段
        warn.setWarnStatus(false); // 未处理状态
        warn.setRecordTime(new Date()); // 记录生成时间

        // 保存告警
        boolean saveSuccess = this.save(warn);
        if (saveSuccess) {
            log.info("成功生成告警：区域[{}]，类型[{}]，等级[{}]，值[{}%]",
                    analyse.getAreaName(), warnType.getWarnName(), warnLevel, fieldValue);
        } else {
            log.error("告警保存失败：区域[{}]，类型[{}]",
                    analyse.getAreaName(), warnType.getWarnName());
        }
    }
}
